/*	--- 使用CompletableFuture(异步回调结果) --- 

使用Future获得【异步执行】结果时，要么调用阻塞方法get()，要么轮询看isDone()是否为true

这两种方法都不是很好，因为‘主线程’也会被迫等待。

------------------

从Java 8开始引入了【CompletableFuture】

CompletableFuture针对Future做了改进，可以传入【回调对象】，当【异步任务】完成/发生‘异常’时，自动调用‘回调对象 的 回调方法‘。


我们以获取股票价格为例，看看如何使用CompletableFuture： */

// CompletableFuture
import java.util.concurrent.CompletableFuture;

public class Main {
	public static void main(String[] args) throws Exception {
		// 创建异步执行任务
		CompletableFuture<Double> cf = CompletableFuture.supplyAsync(Main::fetchPrice);
			// supply v. 供应,提供
			// Async  n. 异步

		// 如果执行成功:
		cf.thenAccept((result) -> { // return result
			System.out.println("price: " + result);
		});

		// 如果执行异常:
		cf.exceptionally((e) -> { // throw new Exception 
			e.printStackTrace();
			return null;
		});

		// 主线程不要立刻结束, 否则CompletableFuture默认使用的线程池会立刻关闭
		Thread.sleep(200);
		
	}

	static Double fetchPrice() { // fetch v. 售得,卖得某价
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// ...
		}

		if (Math.random() < 0.3) {
			throw new RuntimeException("fetch price failed");
		}

		return 5 + Math.random() * 20;
	}
}


/*
创建一个CompletableFuture是通过CompletableFuture.supplyAsync()实现的，它需要一个实现了Supplier接口的对象： */
public interface Supplier<T> {
	T get();
}


/*
这里我们用lambda语法简化了一下，直接传入Main::fetchPrice

因为Main.fetchPrice()静态方法的签名符合Supplier接口的定义（除了方法名外）。


紧接着，CompletableFuture已经被提交给【默认的线程池】执行了，我们需要定义的是CompletableFuture【完成时】和【异常时】需要回调的‘实例’。

------------------------

Thread完成时，CompletableFuture会调用Consumer对象：  */
public interface Consumer<T> { // consumer n. 消费者,用户
	void accept(T t);
}


// Thread异常时，CompletableFuture会调用Function对象：
public interface Function<T, R> {
	R apply(T t);
}


/*
这里我们都用lambda语法简化了代码。

------------------

可见CompletableFuture的优点是：

	· 异步任务结束时，会自动回调某个对象的方法；
	· 异步任务出错时，会自动回调某个对象的方法；
	· 主线程设置好回调后，不再关心异步任务的执行。

------------------

如果只是实现了【异步回调机制】，我们还看不出CompletableFuture相比Future的优势。

CompletableFuture更强大的功能是：【多个CompletableFuture】可以【串行执行】。

例如，定义2个CompletableFuture，

第1个CompletableFuture根据 证券名称 查询 证券代码，
第二个CompletableFuture根据 证券代码 查询 证券价格，

这两个CompletableFuture实现【串行操作】如下： */
import java.util.concurrent.CompletableFuture;

public class Main {
	public static void main(String[] args) throws Exception {
		// 第一个任务
		CompletableFuture<String> cfQuery = CompletableFuture.supplyAsync(() -> {
			return queryCode("中国石油");
		});

		// cfQuery成功后继续执行下一个任务
		CompletableFuture<Double> cfFetch = cfQuery.thenApplyAsync((code) -> { // Apply v. 请求
			return fetchPrice(code);
		});

		// cfFetch成功后打印结果
		cfFetch.thenAccept((result) -> {
			System.out.println("price: " + result);
		});

		// 主线程不要立刻结束, 否则CompletableFuture默认使用的【线程池】会立刻关闭
		Thread.sleep(2000);
	}

	static String queryCode(String name) {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// ...
		}

		return "601857";
	}

	static Double fetchPrice(String code) {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// ...
		}

		return 5 + Math.random() * 20;
	}
}


/*
除了串行执行外，【多个CompletableFuture】还可以【并行执行】。


---------------------------


例如，我们考虑这样的场景：

同时从‘新浪’和‘网易’查询证券代码，只要任意一个返回结果，就进行下一步查询价格，

查询价格也同时从‘新浪’和‘网易‘查询，只要任意一个返回结果，就完成操作：  */
import java.util.concurrent.CompletableFuture;

public class Main {
	public static void main(String[] args) throws Exception {
		// 2个CompletableFuture执行异步查询:
		CompletableFuture<String> cfQueryFromSina = CompletableFuture.supplyAsync(() -> {
			return queryCode("中国石油", "https://finance.sina.com.cn/code/");
		});

		CompletableFuture<String> cfQueryFrom163 = CompletableFuture.supplyAsync(() -> {
			return queryCode("中国石油", "https://money.163.com/code/");
		});

		// 用anyOf合并为一个新的CompletableFuture:
		CompletableFuture<Object> cfQuery = CompletableFuture.anyOf(cfQueryFromSina, cfQueryFrom163);

	//---------------------------

		// 2个CompletableFuture执行异步查询
		CompletableFuture<Double> cfFetchFromSina = cfQuery.thenApplyAsync((code) -> {
			return fetchPrice((String) code, "https://finance.sina.com.cn/price/");
		});

		CompletableFuture<Double> cfFetchFrom163 = cfQuery.thenApplyAsync((code) -> {
			return fetchPrice((String) code, "https://money.163.com/price/");
		});

		// 用anyOf合并为一个新的CompletableFuture:
		CompletableFuture<Object> cfFetch = CompletableFuture.anyOf(cfFetchFromSina, cfFetchFrom163);

	//----------------------------

		// 最终结果:
		cfFetch.thenAccept((result) -> {
			System.out.println("price: " + result);
		});


		//----------------------------

		// 主线程不要立刻结束,否则CompletableFuture默认使用的ThreadPool会中断关闭
		Thread.sleep(200);
	}


	static String queryCode(String name, String url) {
		System.out.println("query code from " + url + "...");

		try {
			Thread.sleep((long) (Math.random() * 100));
		} catch (InterruptedException e) {
			// ...
		}

		return "601857";
	}


	static Double fetchPrice(String code, String url) {
		System.out.println("query price from " + url + "...");

		try {
			Thread.sleep((long) (Math.random() * 100));
		} catch (InterruptedException e) {
			// ...
		}

		return 5 + Math.random() * 20;
	}
}


/*
上述逻辑实现的异步查询规则实际上是：
ps: 一定程度上借助了‘物理时间’实现了【顺序】,所以仅对最后一个cfFetch.thenAccept((resulet) -> {...}); 

		CompletableFuture.supplyAsync()         
	┌─────────────┐ ┌─────────────┐
	│ Query Code  │ │ Query Code  │
	│  from sina  │ │  from 163   │
	└─────────────┘ └─────────────┘
	       │               │
	       └───────┬───────┘
	               ▼
	        ┌─────────────┐
	        │    anyOf()  │ cfQuery = CompletableFuture.
	        └─────────────┘
	               │
	       ┌───────┴────────┐
	       ▼                ▼
	    cfQuery.thenApplyAsync();
	┌─────────────┐  ┌─────────────┐
	│ Query Price │  │ Query Price │
	│  from sina  │  │  from 163   │
	└─────────────┘  └─────────────┘
	       │                │
	       └────────┬───────┘
	                ▼
	         ┌─────────────┐
	         │    anyOf()  │ CompletableFuture<T> cfFetch
	         └─────────────┘
	                │
	                ▼
	         ┌─────────────┐
	         │Display Price│
	         └─────────────┘
	CompletableFuture.thenAccept((result) -> {..});
		

除了【CompletableFuture.anyOf(x1, x2);】可以实现“任意一个CompletableFuture成功,则同一类anyOf()组里的Thread全部结束”，

【allOf()】可以实现“所有CompletableFuture都必须成功”，这些组合操作可以实现‘非常复杂的异步流程控制’。


最后我们注意CompletableFuture的命名规则：

	· xxx()：表示该方法将继续在已有的线程中执行；
	· xxxAsync()：表示将‘异步’在【线程池】中执行。


----------------------------------------------*/



/*-------------------------------------


#	---- 使用CompletableFuture の 小结 ---- 

1. CompletableFuture可以指定异步处理流程：

	· thenAccept()  处理正常结果;
	· exceptional()  处理异常结果;

	· thenApplyAsync()  用于‘串行化’另一个CompletableFuture;
		(即:承接上一个cf.supplyAsync()/cf.thenApplyAsync()的anyOf()/allOf()完成后的【下一轮Async执行任务】)

	· anyOf() 线程集合内任意一个成功返回,则继续(并行化,任1)
	· allOf() 线程集合内都必须成功返回,才继续(并行化,全1)


总结
// 先使用CF.supplyAsync()
	CompletableFuture<T> cf_q_1 = CompletableFuture.supplyAsync(() -> {
		return Function(T);
	});

	CompletableFuture<T> cf_q_2 = CompletableFuture.supplyAsync(() -> {
		return Function(T);
	});

	CompletableFuture<Object> cf_q = CompletableFuture.anyOf(cf_q_1, cf_q_2);

	-------------

// 再使用CF.thenApplyAsync()
	CompletableFuture<K> cf_f_1 = CompletableFuture.thenAppleyAsync((parameter) -> {
		return Function(parameter, other_parameter);
			// return Type=K
	});

	--------------

	cf_f_1.thenAccept((result) -> {
		System.out.println(result);
	});

----------------------------

如图：


		CompletableFuture.supplyAsync()         
	┌─────────────┐ ┌─────────────┐
	│ Query Code  │ │ Query Code  │
	│  from sina  │ │  from 163   │
	└─────────────┘ └─────────────┘
	       │               │
	       └───────┬───────┘
	               ▼
	        ┌─────────────┐
	        │    anyOf()  │ cfQuery = CompletableFuture.
	        └─────────────┘
	               │
	       ┌───────┴────────┐
	       ▼                ▼
	    cfQuery.thenApplyAsync();
	┌─────────────┐  ┌─────────────┐
	│ Query Price │  │ Query Price │
	│  from sina  │  │  from 163   │
	└─────────────┘  └─────────────┘
	       │                │
	       └────────┬───────┘
	                ▼
	         ┌─────────────┐
	         │    anyOf()  │ CompletableFuture<T> cfFetch
	         └─────────────┘
	                │
	                ▼
	         ┌─────────────┐
	         │Display Price│
	         └─────────────┘



*/








